package scales.xml
import scales.utils.error
import scales.utils.{LeftLike, RightLike}
import scales.xml.impl.{FromParser, NotFromParser, IsFromParser}
sealed trait XmlVersion{
val version : String
}
case object Xml11 extends XmlVersion {
val version = "1.1"
}
case object Xml10 extends XmlVersion {
val version = "1.0"
}
import impl.QNameCharUtils._
sealed trait UnderlyingNamespace {
val uri : String
override def hashCode = uri.hashCode
override def equals( other : Any ) = other match {
case ons : UnderlyingNamespace =>
(this eq ons) || (uri == ons.uri)
case _ => false
}
}
sealed trait Namespace extends UnderlyingNamespace {
def apply( local : String )(implicit ver : XmlVersion, fromParser : FromParser) = UnprefixedQName(local, this)
def apply( prefix : String, local : String)(implicit ver : XmlVersion, fromParser : FromParser) = PrefixedQName(local, prefixed(prefix))
def prefixed( prefix : String )(implicit ver : XmlVersion, fromParser : FromParser) = PrefixedNamespace(this, prefix)
def prefixed( prefix : String, local : String)(implicit ver : XmlVersion, fromParser : FromParser) : PrefixedQName = PrefixedQName(local, prefixed(prefix))
}
object EmptyNamespace extends UnderlyingNamespace {
final val uri = ""
}
private[xml] object NamespaceImpl {
import Namespace._
def swapForKnown( validUri : String )(implicit ver : XmlVersion, fromParser : FromParser) =
validUri match {
case `xmlnsNS` => xmlns
case `xmlNS` => xml
case `xsiNS` => xsi
case _ => new Namespace{ val uri = validUri }
}
}
object Namespace {
val xmlNS = "http://www.w3.org/XML/1998/namespace"
val xmlnsNS = "http://www.w3.org/2000/xmlns/"
val xsiNS = "http://www.w3.org/2001/XMLSchema-instance"
val xmlns: Namespace = new Namespace{ val uri = xmlnsNS }
val xml: Namespace = new Namespace{ val uri = xmlNS }
val xsi: Namespace = new Namespace{ val uri = xsiNS }
import NamespaceImpl.swapForKnown
def apply( validUri : String )(implicit ver : XmlVersion, fromParser : FromParser) : Namespace =
if (fromParser eq NotFromParser)
if (validXmlNamespace(validUri))
swapForKnown(validUri)
else
error("Namespaces must have valid URIs, '"+validUri+"' is invalid for Xml "+ver.version)
else
swapForKnown(validUri)
def unapply( n : Namespace) = Some((n.uri))
}
sealed trait PrefixedNamespace {
val ns : Namespace
val prefix : String
def apply( local : String )(implicit ver : XmlVersion, fromParser : FromParser) = PrefixedQName(local, this)
override def hashCode =
(ns.hashCode * 31) + prefix.hashCode
override def equals( other : Any ) = other match {
case opns : PrefixedNamespace => ns == opns.ns && prefix == opns.prefix
case _ => false
}
}
object PrefixedNamespace {
val xmlnsPRE = "xmlns"
val xmlPRE = "xml"
private[xml] def swapForKnown( nsprefix : String ) =
nsprefix match {
case `xmlnsPRE` => xmlnsPRE
case `xmlPRE` => xmlPRE
case _ => nsprefix
}
private[xml] def verifyConstraint( pre : String, ns : Namespace,
agpre : String, agns : String) {
if (((ns.uri eq agns) && (pre ne agpre)) ||
((pre eq agpre) && (ns.uri ne agns))) {
error("The namespace '"+agns+"' can only be bound to prefix '"+agpre+"'")
}
}
private[xml] def checkPrefix( nsprefix : String, ns : Namespace )(implicit ver : XmlVersion) =
if (validXmlPrefix(nsprefix)) {
val x = swapForKnown(nsprefix)
verifyConstraint(x, ns, xmlPRE, Namespace.xmlNS)
verifyConstraint(x, ns, xmlnsPRE, Namespace.xmlnsNS)
x
} else error("The prefix '"+nsprefix+"' is not valid")
def apply(namespace : Namespace, nsprefix : String)(implicit ver : XmlVersion, fromParser : FromParser) : PrefixedNamespace = new PrefixedNamespace {
val ns = namespace
val prefix =
if (fromParser eq NotFromParser)
checkPrefix(nsprefix, namespace)
else
swapForKnown(nsprefix)
}
def unapply( p : PrefixedNamespace) = Some((p.ns, p.prefix))
}